class Captcha {
  constructor(el, options) {
    /* 生成验证码到这个元素里面 */
    this.el = el;
    this.options = {
      /* canvas的ID */
      canvasId: (options && options.canvasId) || "captchaImg",
      /* canvas的宽 */
      width: (options && options.width) || 100,
      /* canvas的高 */
      height: (options && options.height) || 30,
      /* 验证码长度 */
      length: (options && options.length) || 4,
      /* 图形验证码默认类型blend:数字字母混合类型、number:纯数字、letter:纯字母 */
      type: (options && options.type) || "blend",
      /* 校验失败是否立即刷新验证码 */
      refresh: (options && options.refresh) || false,
    };
    this.numArr = "0123456789".split("");
    /* 排除一些相似字符 l o I O U V */
    this.letterArr = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTWXYZ".split("");
    this.blendArr = this.numArr.concat(this.letterArr);
    /* 验证码 */
    this.vcode = "";
    /* 验证是否成功标识 */
    this.flag = false;
    /* 阉割this对象,隐藏一些数据 */
    this._this = {};
    this._this.flag = this.flag;
    this._this.success = (cb) => this.success(cb);
    this._this.fail = (cb) => this.fail(cb);
    this.init();
  }
  init() {
    let con = document.querySelector(this.el);
    let canvas = document.createElement("canvas");
    /* 如果元素有宽度p的元素有宽高就使用宽高，没有就使用传进来的宽高 */
    this.options.width =
      con.offsetWidth > 0 ? con.offsetWidth : this.options.width;
    this.options.height =
      con.offsetHeight > 0 ? con.offsetHeight : this.options.height;

    canvas.id = this.options.canvasId;
    canvas.width = this.options.width;
    canvas.height = this.options.height;
    canvas.innerText = "您的浏览器版本不支持canvas";
    canvas.style.cursor = "pointer";
    con.appendChild(canvas);
    this.draw();
    canvas.onclick = () => {
      this.draw();
    };
  }
  draw() {
    let canvas = document.getElementById(this.options.canvasId);
    if (!canvas.getContext) return;
    let ctx = canvas.getContext("2d");
    ctx.textBaseline = "middle";
    ctx.textAlign = "center";
    /* 清空画布 */
    ctx.clearRect(0, 0, this.options.width, this.options.height);
    /* 绘制之前清空验证码变量 */
    this.vcode = "";
    /* 验证标识 */
    this.flag = false;
    /* 判断验证码类型 */
    let captchaArr =
      this.options.type == "number"
        ? this.numArr
        : this.options.type == "letter"
        ? this.letterArr
        : this.blendArr;

    for (let i = 0; i < this.options.length; i++) {
      let txt = captchaArr[this.randomNum(0, captchaArr.length)];
      this.vcode += txt;
      /* 随机弧度 */
      let deg = (this.randomNum(-30, 30) * Math.PI) / 180;
      let x = (this.options.width / (this.options.length + 1)) * (i + 1);
      let y = this.options.height / 2;
      ctx.font = "bold 20px 微软雅黑";
      ctx.fillStyle = this.randomColor();
      ctx.translate(x, y);
      ctx.rotate(deg);
      ctx.fillText(txt, 0, 0);
      ctx.rotate(-deg);
      ctx.translate(-x, -y);
    }
    /* 验证码上显示线条 */
    for (let i = 0; i <= 5; i++) {
      ctx.strokeStyle = this.randomColor();
      ctx.beginPath();
      ctx.moveTo(
        this.randomNum(0, this.options.width),
        this.randomNum(0, this.options.height)
      );
      ctx.lineTo(
        this.randomNum(0, this.options.width),
        this.randomNum(0, this.options.height)
      );
      ctx.stroke();
    }
    /* 验证码上显示小点 */
    for (let i = 0; i <= 30; i++) {
      ctx.strokeStyle = this.randomColor();
      ctx.beginPath();
      let x = this.randomNum(0, this.options.width);
      let y = this.randomNum(0, this.options.height);
      ctx.moveTo(x, y);
      ctx.lineTo(x + 1, y + 1);
      ctx.stroke();
    }
  }
  randomNum(min, max) {
    return Math.floor(Math.random() * (max - min) + min);
  }
  randomColor() {
    let r = this.randomNum(0, 255);
    let g = this.randomNum(0, 255);
    let b = this.randomNum(0, 255);
    return "rgb(" + r + "," + g + "," + b + ")";
  }
  /* 校验验证码,返回bool值 */
  validate(code) {
    this.flag = Boolean(code && code.toLowerCase() == this.vcode.toLowerCase());
    if (!this.flag && this.options.refresh) this.draw();
    return this.flag;
  }
  /* 校验验证码, 返回阉割this对象,保证可链式调用,执行回调函数 */
  verify(code) {
    this.flag = Boolean(code && code.toLowerCase() == this.vcode.toLowerCase());
    if (!this.flag && this.options.refresh) this.draw();
    return this._this;
  }
  success(callback) {
    this.flag && callback && callback();
    return this._this;
  }
  fail(callback) {
    !this.flag && callback && callback();
    return this._this;
  }
}
!(function () {
  console.log("%c加载captcha.js", "color:blue;");
})();
/*
<!-- 使用方式 -->
<input type="text" id="code"><span id="tips"></span>
<p style="width:100px;height:30px;" id="captcha"></p>
<button type="button" id="btn">验证</button>
<script src="./js/captcha.js"></script>
<script>
    let btn = document.querySelector('#btn');
    let code = document.querySelector('#code');
    let tips = document.querySelector('#tips');
    let captcha = new Captcha('#captcha', {
        refresh: true
    });
    btn.onclick = function () {
        // 链式调用验证
        captcha.verify(code.value).success(function () {
            tips.innerText = 'ok'
        }).fail(function () {
            tips.innerText = 'fail';
        });
        // 普通验证
        let flag = captcha.validate(code.value)
        tips.title = flag;
    }
</script>
*/
